Mommy morse
The little warm up with daddy morse is now over, let’s see what mommy has to offer !
What is this about ?
Daddy morse was just about transmitting on or off signals (well, kindof). Mommy morse wants us to fiddle with frequencies and all: I’m pretty sure that this whole thing is about Frequency modulation/Frequency shift keying. We have to encode data the following way:
- sample rate: 24kHz
.
: 5kHz carrier wave for 1ms-
: 5kHz carrier wave for 5ms- Space between two letters: 1kHz carrier wave for 5ms
- Space between two words: 1kHz carrier wave for 20ms
To flag this challenge, I was at first trying to do everything in python with numpy, just as I did with Daddy morse. In the end, I just kept the message -> AM part and did the rest in Gnu Radio.
Message -> AM
Here is the script that I used to generate my AM signal:
import numpy as np
SAMP_RATE = 24e3
TIMING_DOT = 1/1000
TIMING_DASH = 5/1000
TIMING_SEP_LETTER = 5/1000
TIMING_SPACE = 20/1000
dot_count = int(TIMING_DOT * SAMP_RATE)
dash_count = int(TIMING_DASH * SAMP_RATE)
letters_count = int(TIMING_SEP_LETTER * SAMP_RATE)
word_count = int(TIMING_SPACE * SAMP_RATE)
alphabet = { 'A':'.-', 'B':'-...',
'C':'-.-.', 'D':'-..', 'E':'.',
'F':'..-.', 'G':'--.', 'H':'....',
'I':'..', 'J':'.---', 'K':'-.-',
'L':'.-..', 'M':'--', 'N':'-.',
'O':'---', 'P':'.--.', 'Q':'--.-',
'R':'.-.', 'S':'...', 'T':'-',
'U':'..-', 'V':'...-', 'W':'.--',
'X':'-..-', 'Y':'-.--', 'Z':'--..',
'1':'.----', '2':'..---', '3':'...--',
'4':'....-', '5':'.....', '6':'-....',
'7':'--...', '8':'---..', '9':'----.',
'0':'-----', ', ':'--..--', '.':'.-.-.-',
'?':'..--..', '/':'-..-.', '-':'-....-',
'(':'-.--.', ')':'-.--.-'}
def build(phrase):
res = []
for w in phrase.split(" "):
tmp = ""
for l in w:
if l not in alphabet:
pass
else:
tmp += "{} ".format(alphabet[l])
res.append(tmp[:-1])
return res
def generate(morse):
res = []
for w in morse:
for c in w:
if c == ".":
data = [(1+1j) for _ in range(dot_count)] + [0j for _ in range(dot_count)]
elif c == "-":
data = [(1+1j) for _ in range(dash_count)] + [0j for _ in range(dot_count)]
else:
data = [0j for _ in range(letters_count)]
res = res[:-dot_count]
res.extend(data)
if w[-1] == '.' or w[-1] == '-':
res = res[:-dot_count]
res.extend([0j] * word_count)
res = res[:-word_count]
return np.array(res,dtype=np.complex64)
sentence = "CAN I GET THE FLAG"
morse = build(sentence)
data = generate(morse)
filename = sentence.replace(" ", "-").lower()
print(f"Writing data to {filename}.iq")
with open(f"{filename}.iq", "wb") as file:
file.write(data)
Quick launch:
1 ❯ python hardware/mommymorse/script.py
Writing data to can-i-get-the-flag.iq
0 ❯
And let’s see if URH appreciates what I’ve done:
It does !
AM -> FM
Now that is the fun part of the challenge! Here’s what I’ve done:
You can open and try this circuit by yourself with script.grc
.
Kesseussai ????
Okay sorry, please bear with me.
First and foremost, set the samp_rate variable to 24KHz as specified by the challenge, this is important.
Then, load the AM signal with a File Source block (do not forget to turn off repeat on this block or your FM file won’t work with this challenge).
Create a constant source block that always outputs (1 + 1j)
and link both that block and the file source to a subtract block: this will give us the opposite of our AM signal.
Create two signal sources, one at 1KHz (for the spaces) and one at 5KHz (for the non-spaces chars), they will be used to convert that AM signal to FM. Now create two multiply blocks:
- Link the subtract block and the 1KHz signal source with the first multiply
- Link the File source and the 5KHz signal with the second multiply
This will transform this (AM):
Into this (FM):
We still need to add these two multiply blocks, so create add Add block and link them with it.
And that’s pretty much it, link your add block to a file sink (and some graphs if you like to visualize your hard work) and voila:
Lemme get the flag
Just a little edit to the client.py
a bit:
from pwn import *
import numpy as np
import base64
HOST = args.HOST or "challenges.france-cybersecurity-challenge.fr"
PORT = args.PORT or 2252
c = remote(HOST, PORT)
hello_signal = np.fromfile("res.iq", dtype = np.complex64)
encoded_signal = base64.b64encode(hello_signal.tobytes())
c.recvuntil(b"> ")
c.sendline(encoded_signal)
print(c.recvline())
Now just go ahead and execute it:
0 hardware/mommy morse❯ python client.py
[+] Opening connection to challenges.france-cybersecurity-challenge.fr on port 2252: Done
b'Well done: FCSC{490b88345a22d35554b3e319b1200b985cc7683e975969d07841cd56dd488649}\n'
[*] Closed connection to challenges.france-cybersecurity-challenge.fr port 2252